package org.dxy.domain.handler.route;

import com.google.common.eventbus.EventBus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.adapter.IEventRepository;
import org.dxy.domain.adapter.IdGenerator;
import org.dxy.domain.adapter.port.CommandHandler;
import org.dxy.domain.adapter.repository.IRouteRepository;
import org.dxy.domain.command.route.CreateRouteCommand;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.exception.DomainException;
import org.dxy.domain.model.aggregate.Route;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;

/**
 * @description: 创建工艺路线命令处理器
 * @author: dxy
 * @createTime: 2025/6/26 10:30
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CreateRouteCommandHandler implements CommandHandler<CreateRouteCommand, Long> {

    private final IRouteRepository routeRepository;
    private final EventBus eventBus;
    private final IdGenerator idGenerator;
    private final IEventRepository eventRepository;

    @Transactional
    @Override
    public CommandResult<Long> handle(CreateRouteCommand command) {
        try {
//            // 1. 生成工艺路线ID
            Long routeId = idGenerator.generate();

            // 2. 创建聚合根并内部附带事件
            Route route = Route.create(routeId,command);

            // 3. 保存聚合根
            routeRepository.save(route);

            List<DomainEvent> events = route.getDomainEvents();

            // 4. 保存事件到事件存储，获取固定的事件ID列表
            List<Long> eventIds = eventRepository.saveEvents(events);

            // 5. 创建事件副本用于发布
            List<DomainEvent> eventsCopy = new ArrayList<>(events);

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    // 使用事务提交前保存的事件副本
                    eventsCopy.forEach(eventBus::post);

                    // 当事件发布成功后，会把这个字段标记为 true；（如果系统崩溃或重启，可以扫描未发布的事件（published = false）重新发布，保证"最终一致性"。）
                    eventRepository.markEventsPublished(eventIds);

                    // 7. 清理事件
                    route.clearDomainEvents();
                }
            });

            log.info("创建工艺路线成功, routeId={}, command={}", routeId, command);
            return CommandResult.success(routeId, "创建工艺路线成功");
        } catch (DomainException e) {
            return CommandResult.fail(null, e.getMessage()); // 业务错误
        } catch (RuntimeException e) {
            log.error("系统异常", e); // 系统异常
            return CommandResult.fail(null, "系统异常，请稍后重试");
        }
    }

}